{
  File   : S2DSWCanvas.pas (This unit is a part of S2DE)
  S2DE   : Simple 2D Engine (software render)
  Copyright (c) 2008, Kagamma
  License: GPLv3

-----------------------------------------------------------
  Unit nay chua cac thu tuc & ham can thiet cho xu ly do hoa
  co ban & bo nho cho S2DE. Hau het chung duoc viet bang hop
  ngu (1 so lenh su dung MMX technology) nen rat nhanh.
}

unit S2DSWCanvas;

{$INCLUDE S2DE.INC}

interface

uses
  Windows, S2DTypes, SysUtils;

// Basic canvas
// Cac thu tuc/ham co chu "Add" deu co nghia la "cong" vao buffer, co chu
// "Sub" nghia la "tru" vao buffer

  // khoi tao & xoa bo nho
  {$IFDEF OLDCALL}
  function  MemSize32(Addr: DWord): DWord;
  {$ENDIF}
  procedure AllocMem32(var Addr: DWord; ASize: DWord);
  procedure FreeMem32(var Addr: DWord);

  // thay doi resolution cua window
  procedure SetResolution(Width, Height: Word);
  procedure ResetResolution;

  // Xoa toan bo buffer = gia tri mau Color
  procedure ClearBuffer(var Buf: TBuffer; Color: DWord);
  // Copy toan bo data trong source sang dest (luu y 2 buffer phai cung
  // resolution)
  procedure SwapBuffer(var Dest, Source: TBuffer);
  // khoi tao buffer
  procedure InitBuffer(var Buf: TBuffer; Width, Height: DWord; const Clear: Boolean = TRUE);
  // xoa buffer
  procedure FreeBuffer(var Buf: TBuffer);

  // ve 1 diem vao buffer voi mau color
  procedure PutPixel(var Buf: TBuffer; X, Y: LongInt; Color: DWord);
  // lay gia tri mau tai 1 diem
  function  GetPixel(var Buf: TBuffer; X, Y: LongInt): DWord;
  procedure AddPixel(var Buf: TBuffer; X, Y: LongInt; Color: DWord);
  procedure SubPixel(var Buf: TBuffer; X, Y: LongInt; Color: DWord);

  // ve doan thang theo truc X
  procedure HorzLine(var Buf: TBuffer; X1, X2, Y: LongInt; Color: DWord);
  // ve doan thang theo truc Y
  procedure VertLine(var Buf: TBuffer; X, Y1, Y2: LongInt; Color: DWord);
  procedure HorzLineAdd(var Buf: TBuffer; X1, X2, Y: LongInt; Color: DWord);
  procedure VertLineAdd(var Buf: TBuffer; X, Y1, Y2: LongInt; Color: DWord);
  procedure HorzLineSub(var Buf: TBuffer; X1, X2, Y: LongInt; Color: DWord);
  procedure VertLineSub(var Buf: TBuffer; X, Y1, Y2: LongInt; Color: DWord);

  // ve doan thang
  procedure Line(var Buf: TBuffer; X1, Y1, X2, Y2: LongInt; Color: DWord);
  procedure LineAdd(var Buf: TBuffer; X1, Y1, X2, Y2: LongInt; Color: DWord);
  procedure LineSub(var Buf: TBuffer; X1, Y1, X2, Y2: LongInt; Color: DWord);

  // Ve & to mau 1 hinh chu nhat
  procedure FillBar(var Buf: TBuffer; X1, Y1, X2, Y2: LongInt; Color: DWord);
  procedure AddBar(var Buf: TBuffer; X1, Y1, X2, Y2: LongInt; Color: DWord);
  procedure SubBar(var Buf: TBuffer; X1, Y1, X2, Y2: LongInt; Color: DWord);

  // convert mau theo RGB
  function  RGBToDWord(R, G, B: Byte): DWord;
  function  DWordToRGB(Color: DWord): TRGB; assembler;
  // load 1 file BMP vao buffer
  procedure LoadBMP(var Buf: TBuffer; AName: String);

  // ve buffer source vao buffer dest tai vi tri X, Y
  procedure PutBuffer(var Dest, Source: TBuffer; X, Y: LongInt); overload;
  // ve buffer source vao buffer dest tai vi tri X, Y, transparent
  // color = Mask
  procedure PutBuffer(var Dest, Source: TBuffer; X, Y: LongInt; Mask: DWord); overload;
  // ve 1 phan cua buffer source tai vi tri XPos, YPos, kich thuoc Width,
  // Height vao buffer dest tai vi tri X, Y
  procedure PutBuffer(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt); overload;
  // ve 1 phan cua buffer source tai vi tri XPos, YPos, kich thuoc Width,
  // Height vao buffer dest tai vi tri X, Y, transparent color = Mask
  procedure PutBuffer(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt; Mask: DWord); overload;

  procedure AddBuffer(var Dest, Source: TBuffer; X, Y: LongInt); overload;
  procedure AddBuffer(var Dest, Source: TBuffer; X, Y: LongInt; Mask: DWord); overload;
  procedure AddBuffer(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt); overload;
  procedure AddBuffer(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt; Mask: DWord); overload;

  procedure SubBuffer(var Dest, Source: TBuffer; X, Y: LongInt); overload;
  procedure SubBuffer(var Dest, Source: TBuffer; X, Y: LongInt; Mask: DWord); overload;
  procedure SubBuffer(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt); overload;
  procedure SubBuffer(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt; Mask: DWord); overload;

  // ve buffer source lat nguoc theo huong truc X vao buffer dest tai vi tri
  // X, Y
  procedure PutBufferMirrorX(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt); overload;
  // ve buffer source lat nguoc theo huong truc X vao buffer dest tai vi tri
  // X, Y, transparent color = Mask
  procedure PutBufferMirrorX(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt; Mask: DWord); overload;

  procedure AddBufferMirrorX(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt); overload;
  procedure AddBufferMirrorX(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt; Mask: DWord); overload;

  procedure SubBufferMirrorX(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt); overload;
  procedure SubBufferMirrorX(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt; Mask: DWord); overload;

  // Xuat 1 chuoi van ban tex ra man hinh
  procedure SysText(Dest: TBuffer; X, Y: LongInt; Tex: String; Color: LongInt);

  // stretch image
  procedure StretchBuffer(var Dest, Source: TBuffer; X, Y, ResizeX, ResizeY: LongInt);

  {  rotate image
     ham thuc hien kha cham do phai pre-calculate 1 dien tich kha rong lon -
     can cai thien ve mat thuat toan }
  procedure RotateBuffer(var Dest, Source: TBuffer; X, Y, Angle: LongInt);

implementation

uses S2DMain, S2DLog, S2DSysFont;

{$IFDEF OLDCALL}
function  MemSize32(Addr: DWord): DWord; assembler;
// tu FPC 2xx ko can goi lenh nay nua
asm
    cmp Addr,0
    je  @Fd
    mov esi,Addr
    mov eax,[esi-4]
@Fd:
end;
{$ENDIF}

procedure AllocMem32(var Addr: DWord; ASize: DWord);
// Khoi tao 1 vung nho co kich thuoc ASize
begin
  if Addr = 0 then
  begin
    GetMem(Pointer(Addr), ASize);
    Inc(S2DInfo.TotalAllocMemory, MemSize(Pointer(Addr)));
    if S2DInfo.TotalAllocMemory>S2DInfo.MaxAllocMemory then
      S2DInfo.MaxAllocMemory:= S2DInfo.TotalAllocMemory;
  end
  else
  begin
    Dec(S2DInfo.TotalAllocMemory, MemSize(Pointer(Addr)));
    ReAllocMem(Pointer(Addr), ASize);
    Inc(S2DInfo.TotalAllocMemory, MemSize(Pointer(Addr)));
    if S2DInfo.TotalAllocMemory>S2DInfo.MaxAllocMemory then
      S2DInfo.MaxAllocMemory:= S2DInfo.TotalAllocMemory;
  end;
end;

procedure FreeMem32(var Addr: DWord);
// Giai phong Addr
begin
  if Addr<>0 then
  begin
    Dec(S2DInfo.TotalAllocMemory, MemSize(Pointer(Addr)));
    FreeMem(Pointer(Addr));
    Addr:= 0;
  end;
end;

procedure SetResolution(Width, Height: Word);
var Counter: Word;
begin
  Counter:= -1;
  repeat
    Inc(Counter);
    S2DInfo.DeviceOK:= EnumDisplaySettings(nil, Counter, @S2DInfo.Device);
  until NOT S2DInfo.DeviceOK OR
        (Counter>65534) OR
        (S2DInfo.Device.dmPelsWidth = Width) AND
        (S2DInfo.Device.dmPelsHeight = Height) AND
        (S2DInfo.Device.dmBitsPerPel = 32);
  if S2DInfo.DeviceOk then
    ChangeDisplaySettings(@S2DInfo.Device, 0);
end;

procedure ResetResolution;
begin
  if S2DInfo.DeviceOK then
    ChangeDisplaySettings(nil, 0);
end;

procedure ClearBuffer(var Buf: TBuffer; Color: DWord); assembler;
// Xoa buffer = gia tri Color
asm
   { mov esi,Buf
    mov edx,Color
    mov eax,[esi+12]
    shr eax,2
    mov edi,[esi]
    xor ecx,ecx
@Lp:
    inc ecx
    mov [edi],edx
    add edi,4
    cmp ecx,eax
    jne @Lp
// old DPMI16 transfer - ko hoat dong trong 32bit :-<
    cld
    mov edi,Buf
    mov ecx,[edi+12]
    shr ecx,2
    mov eax,Color
    mov edi,[edi]
    stosd    }
    mov esi,Buf
    mov eax,Color
    movd mm0,eax
    movd mm1,eax
    psllq mm0,32
    paddusw mm0,mm1
    mov eax,[esi+12]
    shr eax,3
    mov edi,[esi]
    xor ecx,ecx
@Lp:
    inc ecx
    movq [edi],mm0
    add edi,8
    cmp ecx,eax
    jne @Lp
    emms
end;

procedure SwapBuffer(var Dest, Source: TBuffer); assembler;
// Copy buffer tu source sang dest
asm
    mov esi,Source
    mov edi,Dest
    mov eax,[esi+12]
    mov ebx,[edi+12]
    cmp eax,ebx
    jne @Fd
    shr eax,3
    mov esi,[esi]
    mov edi,[edi]
    xor ecx,ecx
@Lp:
    inc ecx
    movq mm0,[esi]
    movq [edi],mm0
    add esi,8
    add edi,8
    cmp ecx,eax
    jne @Lp
@Fd:
    emms
end;

procedure InitBuffer(var Buf: TBuffer; Width, Height: DWord; const Clear: Boolean = TRUE);
// Khoi tao buffer
begin
  Buf.Width  := Width;
  Buf.Height := Height;
  Buf.MiddleX:= Width shr 1;
  Buf.MiddleY:= Height shr 1;
  Buf.MidXM1 := Width-1;
  Buf.MidYM1 := Height-1;
  Buf.ScanX  := Width shl 2;
  Buf.ScanY  := Height shl 2;
  Buf.Size   := (Width * Height) shl 2;
  Buf.Area   := Width * Height;

  AllocMem32(Buf.Address, Buf.Size);
  if Clear then
    ClearBuffer(Buf, 0);
  Buf.Path:= '';
  {$IFDEF LOG}
  AddLog('(i)', Format('Init buffer: <%d> bytes', [Buf.Size]));
  {$ENDIF}
end;

procedure FreeBuffer(var Buf: TBuffer);
// giai phong buffer
begin
  if Pointer(Buf.Address) <> nil then
  begin
    FreeMem32(Buf.Address);
    Buf.Area   := 0;
    Buf.Width  := 0;
    Buf.Height := 0;
    Buf.MiddleX:= 0;
    Buf.MiddleY:= 0;
    Buf.MidXM1 := 0;
    Buf.MidYM1 := 0;
    Buf.ScanX  := 0;
    Buf.ScanY  := 0;
    {$IFDEF LOG}
    AddLog('(i)', Format('Free buffer: <%d> bytes', [Buf.Size]));
    {$ENDIF}
    if Buf.Path<>'' then
    begin
   //   AddLog('(i)', Format(' >Free Texture: "%s"', [Buf.Path]));
      Buf.Path:= '';
    end;
    Buf.Size:= 0;
  end;
end;

procedure PutLinearPixel(Source: TBuffer; Pos, Color: LongInt); assembler;
asm
    mov esi,Source
    mov eax,Pos
    cmp eax,[esi+16]
    jge @EndP
    mov esi,[esi]
    add esi,eax
    shl eax,2
    mov eax,Color
    mov [esi],eax
@EndP:
end;

function  GetLinearPixel(Source: TBuffer; Pos: LongInt): LongInt; assembler;
asm
    mov esi,Source
    mov eax,Pos
    cmp eax,[esi+16]
    jge @EndP
    mov esi,[esi]
    add esi,eax
    shl eax,2
    mov eax,[esi]
@EndP:
end;

procedure PutPixel(var Buf: TBuffer; X, Y: LongInt; Color: DWord); assembler;
// Ve 1 pixel vao buffer
asm
    mov esi,Buf
    mov eax,[esi+8]
    cmp Y,eax
    jae  @Ed
    mov eax,[esi+4]
    cmp X,eax
    jae  @Ed
    mul Y
    add eax,X
    shl eax,2
    mov esi,[esi]
    add esi,eax
    mov eax,Color
    mov [esi],eax
@Ed:
end;

function  GetPixel(var Buf: TBuffer; X, Y: LongInt): DWord; assembler;
// Lay gia tri color trong buffer
asm
    mov esi,Buf
    mov eax,[esi+8]
    cmp Y,eax
    jae  @Ed
    mov eax,[esi+4]
    cmp X,eax
    jae  @Ed
    mul Y
    add eax,X
    shl eax,2
    mov esi,[esi]
    add esi,eax
    mov eax,[esi]
@Ed:
end;

function  GetUnClipPixel(var Buf: TBuffer; X, Y: LongInt): DWord; assembler;
// "fast" Lay gia tri color trong buffer
asm
    mov esi,Buf
    mov eax,[esi+4]
    mul Y
    add eax,X
    shl eax,2
    mov esi,[esi]
    add esi,eax
    mov eax,[esi]
end;

procedure PutUnClipPixel(var Buf: TBuffer; X, Y: LongInt; Color: DWord); assembler;
// fast pixel
asm
    mov esi,Buf
    mov eax,[esi+4]
    mul Y
    add eax,X
    shl eax,2
    mov esi,[esi]
    add esi,eax
    mov eax,Color
    mov [esi],eax
end;

procedure AddPixel(var Buf: TBuffer; X, Y: LongInt; Color: DWord); assembler;
asm
    mov esi,Buf
    mov eax,[esi+8]
    cmp Y,eax
    jae  @Ed
    mov eax,[esi+4]
    cmp X,eax
    jae  @Ed

    mul Y
    add eax,X
    shl eax,2
    mov esi,[esi]
    add esi,eax
    mov edx,[esi]

    xor ecx,ecx

    mov eax,edx
    shr eax,16
    xor ah,ah
    mov ebx,Color
    shr ebx,16
    add ax,bx
    cmp ax,$FF
    jle @EdRed
    mov al,$FF
@EdRed:
    mov cl,al
    shl ecx,16

    mov al,dh
    xor ah,ah
    mov ebx,Color
    shr ebx,8
    xor bh,bh
    add ax,bx
    cmp ax,$FF
    jle @EdGreen
    mov al,$FF
@EdGreen:
    mov ch,al

    mov al,dl
    xor ah,ah
    mov ebx,Color
    xor bh,bh
    add ax,bx
    cmp ax,$FF
    jle @EdBlue
    mov al,$FF
@EdBlue:
    mov cl,al

    mov [esi],ecx
@Ed:
end;

procedure AddUnClipPixel(var Buf: TBuffer; X, Y: LongInt; Color: DWord); assembler;
// fast "light" pixel
asm
    mov esi,Buf
    mov eax,[esi+4]

    mul Y
    add eax,X
    shl eax,2
    mov esi,[esi]
    add esi,eax
    mov edx,[esi]

    xor ecx,ecx

    mov eax,edx
    shr eax,16
    xor ah,ah
    mov ebx,Color
    shr ebx,16
    add ax,bx
    cmp ax,$FF
    jle @EdRed
    mov al,$FF
@EdRed:
    mov cl,al
    shl ecx,16

    mov al,dh
    xor ah,ah
    mov ebx,Color
    shr ebx,8
    xor bh,bh
    add ax,bx
    cmp ax,$FF
    jle @EdGreen
    mov al,$FF
@EdGreen:
    mov ch,al

    mov al,dl
    xor ah,ah
    mov ebx,Color
    xor bh,bh
    add ax,bx
    cmp ax,$FF
    jle @EdBlue
    mov al,$FF
@EdBlue:
    mov cl,al

    mov [esi],ecx
end;

procedure SubPixel(var Buf: TBuffer; X, Y: LongInt; Color: DWord); assembler;
asm
    mov esi,Buf
    mov eax,[esi+8]
    cmp Y,eax
    jae  @Ed
    mov eax,[esi+4]
    cmp X,eax
    jae  @Ed

    mul Y
    add eax,X
    shl eax,2
    mov esi,[esi]
    add esi,eax
    mov edx,[esi]
    xor ecx,ecx

    mov eax,Color
    mov ebx,edx
    shr eax,16
    shr ebx,16
    cmp al,bl
    ja @Zero1
    sub bl,al
    jmp @EdRed
@Zero1:
    xor bl,bl
@EdRed:
    mov cl,bl
    shl ecx,16

    mov eax,Color
    mov ebx,edx
    cmp ah,bh
    ja @Zero2
    sub bh,ah
    jmp @EdGreen
@Zero2:
    xor bh,bh
@EdGreen:
    mov ch,bh

    mov ebx,edx
    cmp al,bl
    ja @Zero3
    sub bl,al
    jmp @EdBlue
@Zero3:
    xor bl,bl
@EdBlue:
    mov cl,bl

    mov [esi],ecx
@Ed:
end;

procedure SubUnClipPixel(var Buf: TBuffer; X, Y: LongInt; Color: DWord); assembler;
// fast "dim" pixel
asm
    mov esi,Buf
    mov eax,[esi+4]

    mul Y
    add eax,X
    shl eax,2
    mov esi,[esi]
    add esi,eax
    mov edx,[esi]
    xor ecx,ecx

    mov eax,Color
    mov ebx,edx
    shr eax,16
    shr ebx,16
    cmp al,bl
    ja @Zero1
    sub bl,al
    jmp @EdRed
@Zero1:
    xor bl,bl
@EdRed:
    mov cl,bl
    shl ecx,16

    mov eax,Color
    mov ebx,edx
    cmp ah,bh
    ja @Zero2
    sub bh,ah
    jmp @EdGreen
@Zero2:
    xor bh,bh
@EdGreen:
    mov ch,bh

    mov ebx,edx
    cmp al,bl
    ja @Zero3
    sub bl,al
    jmp @EdBlue
@Zero3:
    xor bl,bl
@EdBlue:
    mov cl,bl

    mov [esi],ecx
end;

procedure HorzLine(var Buf: TBuffer; X1, X2, Y: LongInt; Color: DWord); assembler;
asm
    mov esi,Buf
    mov eax,Y
    shr eax,$1F
    cmp eax,1
    je @Ed
    mov eax,Y
    mov edx,[esi+8]
    cmp eax,edx
    jge @Ed

    mov eax,X1
    shr eax,$1F
    cmp eax,1
    je @Check1
    jmp @EdCheck1
@Check1:
    mov eax,X2
    shr eax,$1F
    cmp eax,1
    je @Ed
@EdCheck1:
// if X1=X2
    mov eax,X1
    cmp eax,X2
    jne @PrepareLp
    push Color
    push Y
    push X1
    push Buf
    call PutUnClipPixel
    jmp @Ed
// swap
@PrepareLp:
    mov eax,X1
    mov ebx,X2
    cmp eax,ebx
    jl @NotSwap
    mov X1,ebx
    mov X2,eax

@NotSwap:
    mov ecx,[esi+4]

    mov eax,X1
    shr eax,$1F
    cmp eax,1
    jl @Check2
    xor eax,eax
    mov eax,X1
    jmp @EdCheck2
@Check2:
    mov eax,X1
    cmp eax,ecx
    jle @EdCheck2
    mov X1,ecx
@EdCheck2:

    mov eax,X2
    shr eax,$1F
    cmp eax,1
    jl @Check3
    xor eax,eax
    mov eax,X2
    jmp @EdCheck3
@Check3:
    mov eax,X2
    cmp eax,ecx
    jle @EdCheck3
    mov X2,ecx
@EdCheck3:

    mov ecx,X1
@Lp:
    push Color
    push Y
    push ecx
    push Buf
    call PutUnClipPixel
    inc ecx
    cmp ecx,X2
    jna @Lp
@Ed:
end;

procedure VertLine(var Buf: TBuffer; X, Y1, Y2: LongInt; Color: DWord); assembler;
asm
    mov esi,Buf
    mov eax,X
    shr eax,$1F
    cmp eax,1
    je @Ed
    mov eax,X
    mov ecx,[esi+4]
    cmp eax,ecx
    jge @Ed

    mov eax,Y1
    shr eax,$1F
    cmp eax,1
    je @Check1
    jmp @EdCheck1
@Check1:
    mov eax,Y2
    shr eax,$1F
    cmp eax,1
    je @Ed
@EdCheck1:
// if Y1=Y2
    mov eax,Y1
    cmp eax,Y2
    jne @PrepareLp
    push Color
    push Y1
    push X
    push Buf
    call PutUnClipPixel
    jmp @Ed
// swap
@PrepareLp:
    mov eax,Y1
    cmp eax,ebx
    jl @NotSwap
    mov Y1,ebx
    mov Y2,eax

@NotSwap:
    mov edx,[esi+8]

    mov eax,Y1
    shr eax,$1F
    cmp eax,1
    jl @Check2
    xor eax,eax
    mov eax,Y1
    jmp @EdCheck2
@Check2:
    mov eax,Y1
    cmp eax,edx
    jle @EdCheck2
    mov Y1,ecx
@EdCheck2:

    mov eax,Y2
    shr eax,$1F
    cmp eax,1
    jl @Check3
    xor eax,eax
    mov eax,Y2
    jmp @EdCheck3
@Check3:
    mov eax,Y2
    cmp eax,edx
    jle @EdCheck3
    mov Y2,edx
@EdCheck3:

    mov ecx,Y1
@Lp:
    push Color
    push ecx
    push X
    push Buf
    call PutUnClipPixel
    inc ecx
    cmp ecx,Y2
    jna @Lp
@Ed:
end;

procedure HorzLineAdd(var Buf: TBuffer; X1, X2, Y: LongInt; Color: DWord); assembler;
asm
    mov esi,Buf
    mov eax,Y
    shr eax,$1F
    cmp eax,1
    je @Ed
    mov eax,Y
    mov edx,[esi+8]
    cmp eax,edx
    jge @Ed

    mov eax,X1
    shr eax,$1F
    cmp eax,1
    je @Check1
    jmp @EdCheck1
@Check1:
    mov eax,X2
    shr eax,$1F
    cmp eax,1
    je @Ed
@EdCheck1:
// if X1=X2
    mov eax,X1
    cmp eax,X2
    jne @PrepareLp
    push Color
    push Y
    push X1
    push Buf
    call AddUnClipPixel
    jmp @Ed
// swap
@PrepareLp:
    mov eax,X1
    mov ebx,X2
    cmp eax,ebx
    jl @NotSwap
    mov X1,ebx
    mov X2,eax

@NotSwap:
    mov ecx,[esi+4]

    mov eax,X1
    shr eax,$1F
    cmp eax,1
    jl @Check2
    xor eax,eax
    mov eax,X1
    jmp @EdCheck2
@Check2:
    mov eax,X1
    cmp eax,ecx
    jle @EdCheck2
    mov X1,ecx
@EdCheck2:

    mov eax,X2
    shr eax,$1F
    cmp eax,1
    jl @Check3
    xor eax,eax
    mov eax,X2
    jmp @EdCheck3
@Check3:
    mov eax,X2
    cmp eax,ecx
    jle @EdCheck3
    mov X2,ecx
@EdCheck3:

    mov ecx,X1
@Lp:
    push ecx
    push Color
    push Y
    push ecx
    push Buf
    call AddUnClipPixel
    pop ecx
    inc ecx
    cmp ecx,X2
    jna @Lp
@Ed:
end;

procedure VertLineAdd(var Buf: TBuffer; X, Y1, Y2: LongInt; Color: DWord); assembler;
asm
    mov esi,Buf
    mov eax,X
    shr eax,$1F
    cmp eax,1
    je @Ed
    mov eax,X
    mov ecx,[esi+4]
    cmp eax,ecx
    jge @Ed

    mov eax,Y1
    shr eax,$1F
    cmp eax,1
    je @Check1
    jmp @EdCheck1
@Check1:
    mov eax,Y2
    shr eax,$1F
    cmp eax,1
    je @Ed
@EdCheck1:
// if Y1=Y2
    mov eax,Y1
    cmp eax,Y2
    jne @PrepareLp
    push Color
    push Y1
    push X
    push Buf
    call AddUnClipPixel
    jmp @Ed
// swap
@PrepareLp:
    mov eax,Y1
    mov ebx,Y2
    cmp eax,ebx
    jl @NotSwap
    mov Y1,ebx
    mov Y2,eax

@NotSwap:
    mov edx,[esi+8]

    mov eax,Y1
    shr eax,$1F
    cmp eax,1
    jl @Check2
    xor eax,eax
    mov eax,Y1
    jmp @EdCheck2
@Check2:
    mov eax,Y1
    cmp eax,edx
    jle @EdCheck2
    mov Y1,ecx
@EdCheck2:

    mov eax,Y2
    shr eax,$1F
    cmp eax,1
    jl @Check3
    xor eax,eax
    mov eax,Y2
    jmp @EdCheck3
@Check3:
    mov eax,Y2
    cmp eax,edx
    jle @EdCheck3
    mov Y2,edx
@EdCheck3:

    mov ecx,Y1
@Lp:
    push ecx
    push Color
    push ecx
    push X
    push Buf
    call AddUnClipPixel
    pop ecx
    inc ecx
    cmp ecx,Y2
    jna @Lp
@Ed:
end;

procedure HorzLineSub(var Buf: TBuffer; X1, X2, Y: LongInt; Color: DWord); assembler;
asm
    mov esi,Buf
    mov eax,Y
    shr eax,$1F
    cmp eax,1
    je @Ed
    mov eax,Y
    mov edx,[esi+8]
    cmp eax,edx
    jge @Ed

    mov eax,X1
    shr eax,$1F
    cmp eax,1
    je @Check1
    jmp @EdCheck1
@Check1:
    mov eax,X2
    shr eax,$1F
    cmp eax,1
    je @Ed
@EdCheck1:
// if X1=X2
    mov eax,X1
    cmp eax,X2
    jne @PrepareLp
    push Color
    push Y
    push X1
    push Buf
    call SubUnClipPixel
    jmp @Ed
// swap
@PrepareLp:
    mov eax,X1
    mov ebx,X2
    cmp eax,ebx
    jl @NotSwap
    mov X1,ebx
    mov X2,eax

@NotSwap:
    mov ecx,[esi+4]

    mov eax,X1
    shr eax,$1F
    cmp eax,1
    jl @Check2
    xor eax,eax
    mov eax,X1
    jmp @EdCheck2
@Check2:
    mov eax,X1
    cmp eax,ecx
    jle @EdCheck2
    mov X1,ecx
@EdCheck2:

    mov eax,X2
    shr eax,$1F
    cmp eax,1
    jl @Check3
    xor eax,eax
    mov eax,X2
    jmp @EdCheck3
@Check3:
    mov eax,X2
    cmp eax,ecx
    jle @EdCheck3
    mov X2,ecx
@EdCheck3:

    mov ecx,X1
@Lp:
    push ecx
    push Color
    push Y
    push ecx
    push Buf
    call SubUnClipPixel
    pop ecx
    inc ecx
    cmp ecx,X2
    jna @Lp
@Ed:
end;

procedure VertLineSub(var Buf: TBuffer; X, Y1, Y2: LongInt; Color: DWord); assembler;
asm
    mov esi,Buf
    mov eax,X
    shr eax,$1F
    cmp eax,1
    je @Ed
    mov eax,X
    mov ecx,[esi+4]
    cmp eax,ecx
    jge @Ed

    mov eax,Y1
    shr eax,$1F
    cmp eax,1
    je @Check1
    jmp @EdCheck1
@Check1:
    mov eax,Y2
    shr eax,$1F
    cmp eax,1
    je @Ed
@EdCheck1:
// if Y1=Y2
    mov eax,Y1
    cmp eax,Y2
    jne @PrepareLp
    push Color
    push Y1
    push X
    push Buf
    call SubUnClipPixel
    jmp @Ed
// swap
@PrepareLp:
    mov eax,Y1
    mov ebx,Y2
    cmp eax,ebx
    jl @NotSwap
    mov Y1,ebx
    mov Y2,eax

@NotSwap:
    mov edx,[esi+8]

    mov eax,Y1
    shr eax,$1F
    cmp eax,1
    jl @Check2
    xor eax,eax
    mov eax,Y1
    jmp @EdCheck2
@Check2:
    mov eax,Y1
    cmp eax,edx
    jle @EdCheck2
    mov Y1,ecx
@EdCheck2:

    mov eax,Y2
    shr eax,$1F
    cmp eax,1
    jl @Check3
    xor eax,eax
    mov eax,Y2
    jmp @EdCheck3
@Check3:
    mov eax,Y2
    cmp eax,edx
    jle @EdCheck3
    mov Y2,edx
@EdCheck3:

    mov ecx,Y1
@Lp:
    push ecx
    push Color
    push ecx
    push X
    push Buf
    call SubUnClipPixel
    pop ecx
    inc ecx
    cmp ecx,Y2
    jna @Lp
@Ed:
end;

procedure Line(var Buf: TBuffer; X1, Y1, X2, Y2: LongInt; Color: DWord);
var X, Y, DX, DY, EInc, ENoInc, E: Integer;
begin
  if X2<X1 then begin
    X:= X2;
    X2:= X1;
    X1:= X;
  end;
  if Y2<Y1 then begin
    X:= Y2;
    Y2:= Y1;
    Y1:= X;
  end;
  if X1=X2 then VertLine(Buf, X1, Y1, Y2, Color) else
  if Y1=Y2 then HorzLine(Buf, X1, X2, Y1, Color) else begin
    Y:= Y1;
    DX:= X2-X1;
    DY:= Y2-Y1;
    ENoInc:= DY+DY;
    E:= ENoInc-DX;
    EInc:= E-DX;
    for X:= X1 to X2 do begin
      PutPixel(Buf, X, Y, Color);
      if E<0 then Inc(E, ENoInc) else begin
        Inc(Y);
        Inc(E, EInc);
      end;
    end;
  end;
end;

procedure LineAdd(var Buf: TBuffer; X1, Y1, X2, Y2: LongInt; Color: DWord);
var X, Y, DX, DY, EInc, ENoInc, E: Integer;
begin
  if X2<X1 then begin
    X:= X2;
    X2:= X1;
    X1:= X;
  end;
  if Y2<Y1 then begin
    X:= Y2;
    Y2:= Y1;
    Y1:= X;
  end;
  if X1=X2 then VertLineAdd(Buf, X1, Y1, Y2, Color) else
  if Y1=Y2 then HorzLineAdd(Buf, X1, X2, Y1, Color) else begin
    Y:= Y1;
    DX:= X2-X1;
    DY:= Y2-Y1;
    ENoInc:= DY+DY;
    E:= ENoInc-DX;
    EInc:= E-DX;
    for X:= X1 to X2 do begin
      AddPixel(Buf, X, Y, Color);
      if E<0 then Inc(E, ENoInc) else begin
        Inc(Y);
        Inc(E, EInc);
      end;
    end;
  end;
end;

procedure LineSub(var Buf: TBuffer; X1, Y1, X2, Y2: LongInt; Color: DWord);
var X, Y, DX, DY, EInc, ENoInc, E: Integer;
begin
  if X2<X1 then begin
    X:= X2;
    X2:= X1;
    X1:= X;
  end;
  if Y2<Y1 then begin
    X:= Y2;
    Y2:= Y1;
    Y1:= X;
  end;
  if X1=X2 then VertLineSub(Buf, X1, Y1, Y2, Color) else
  if Y1=Y2 then HorzLineSub(Buf, X1, X2, Y1, Color) else begin
    Y:= Y1;
    DX:= X2-X1;
    DY:= Y2-Y1;
    ENoInc:= DY+DY;
    E:= ENoInc-DX;
    EInc:= E-DX;
    for X:= X1 to X2 do begin
      SubPixel(Buf, X, Y, Color);
      if E<0 then Inc(E, ENoInc) else begin
        Inc(Y);
        Inc(E, EInc);
      end;
    end;
  end;
end;

procedure FillBar(var Buf: TBuffer; X1, Y1, X2, Y2: LongInt; Color: DWord);
assembler;
asm
// zero value
    mov eax,X1
    shr eax,$1F
    cmp eax,1
    je @Z1
@EdZ1:
    mov eax,Y1
    shr eax,$1F
    cmp eax,1
    je @Z2
@EdZ2:
    mov eax,X2
    shr eax,$1F
    cmp eax,1
    je @Z3
@EdZ3:
    mov eax,Y2
    shr eax,$1F
    cmp eax,1
    je @Z4
    jmp @Swap
@Z1:
    xor eax,eax
    mov X1,eax
    jmp @EdZ1
@Z2:
    xor eax,eax
    mov Y1,eax
    jmp @EdZ2
@Z3:
    xor eax,eax
    mov X2,eax
    jmp @EdZ3
@Z4:
    xor eax,eax
    mov Y2,eax

@Swap:
    mov eax,X1
    mov ebx,X2
    cmp eax,ebx
    jl @NotSwapX
    mov X1,ebx
    mov X2,eax
@NotSwapX:

    mov eax,Y1
    mov ebx,Y2
    cmp eax,ebx
    jl @NotSwapY
    mov Y1,ebx
    mov Y2,eax
@NotSwapY:

    mov ecx,Y1
@Lp:
    pusha
    push Color
    push ecx
    push X2
    push X1
    push Buf
    call HorzLine
    popa
    inc ecx
    cmp ecx,Y2
    jng @Lp

@Ed:
end;

procedure AddBar(var Buf: TBuffer; X1, Y1, X2, Y2: LongInt; Color: DWord);
assembler;
asm
// zero value
    mov eax,X1
    shr eax,$1F
    cmp eax,1
    je @Z1
@EdZ1:
    mov eax,Y1
    shr eax,$1F
    cmp eax,1
    je @Z2
@EdZ2:
    mov eax,X2
    shr eax,$1F
    cmp eax,1
    je @Z3
@EdZ3:
    mov eax,Y2
    shr eax,$1F
    cmp eax,1
    je @Z4
    jmp @Swap
@Z1:
    xor eax,eax
    mov X1,eax
    jmp @EdZ1
@Z2:
    xor eax,eax
    mov Y1,eax
    jmp @EdZ2
@Z3:
    xor eax,eax
    mov X2,eax
    jmp @EdZ3
@Z4:
    xor eax,eax
    mov Y2,eax

@Swap:
    mov eax,X1
    mov ebx,X2
    cmp eax,ebx
    jl @NotSwapX
    mov X1,ebx
    mov X2,eax
@NotSwapX:

    mov eax,Y1
    mov ebx,Y2
    cmp eax,ebx
    jl @NotSwapY
    mov Y1,ebx
    mov Y2,eax
@NotSwapY:

    mov ecx,Y1
@Lp:
    pusha
    push Color
    push ecx
    push X2
    push X1
    push Buf
    call HorzLineAdd
    popa
    inc ecx
    cmp ecx,Y2
    jng @Lp

@Ed:
end;

procedure SubBar(var Buf: TBuffer; X1, Y1, X2, Y2: LongInt; Color: DWord);
assembler;
asm
// zero value
    mov eax,X1
    shr eax,$1F
    cmp eax,1
    je @Z1
@EdZ1:
    mov eax,Y1
    shr eax,$1F
    cmp eax,1
    je @Z2
@EdZ2:
    mov eax,X2
    shr eax,$1F
    cmp eax,1
    je @Z3
@EdZ3:
    mov eax,Y2
    shr eax,$1F
    cmp eax,1
    je @Z4
    jmp @Swap
@Z1:
    xor eax,eax
    mov X1,eax
    jmp @EdZ1
@Z2:
    xor eax,eax
    mov Y1,eax
    jmp @EdZ2
@Z3:
    xor eax,eax
    mov X2,eax
    jmp @EdZ3
@Z4:
    xor eax,eax
    mov Y2,eax

@Swap:
    mov eax,X1
    mov ebx,X2
    cmp eax,ebx
    jl @NotSwapX
    mov X1,ebx
    mov X2,eax
@NotSwapX:

    mov eax,Y1
    mov ebx,Y2
    cmp eax,ebx
    jl @NotSwapY
    mov Y1,ebx
    mov Y2,eax
@NotSwapY:

    mov ecx,Y1
@Lp:
    pusha
    push Color
    push ecx
    push X2
    push X1
    push Buf
    call HorzLineSub
    popa
    inc ecx
    cmp ecx,Y2
    jng @Lp

@Ed:
end;

function RGBToDWord(R, G, B: Byte): DWord; assembler;
asm
    xor eax,eax
    mov al,R
    shl eax,16
    mov ah,G
    mov al,B
end;

function  DWordToRGB(Color: DWord): TRGB; assembler;
asm
    mov edi,Result
    mov eax,Color
    mov ebx,eax
    shr eax,16
    mov [edi],al
    mov [edi+1],bh
    mov [edi+2],bl
end;

procedure LoadBMP(var Buf: TBuffer; AName: String);
var FileHeader: BitmapFileHeader;
    InfoHeader: BitmapInfoHeader;
    F         : File;
    I,
    X,
    Y         : LongInt;
    BitmapLength,
    Color,
    ReadBytes : DWord;
    pData     : array of Byte;
begin
  if FileExists(AName) then
  begin
    Assign(F, AName);
    Reset(F, 1);
    BlockRead(F, FileHeader, SizeOf(FileHeader));
    BlockRead(F, InfoHeader, SizeOf(InfoHeader));

    InitBuffer(Buf, InfoHeader.biWidth, InfoHeader.biHeight, FALSE);

    if InfoHeader.biSizeImage<>0 then
      BitmapLength:= InfoHeader.biSizeImage
    else
      BitmapLength:= InfoHeader.biWidth*InfoHeader.biHeight*InfoHeader.biBitCount div 8;

    Buf.Path:= AName;

    Seek(F, FileHeader.bfOffBits);
    SetLength(pData, BitmapLength);
    BlockRead(F, pData[0], BitmapLength);
    I:= 0;
    for Y:= Buf.Height-1 downto 0 do
    begin
      for X:= 0 to Buf.Width-1 do
      begin
        PutUnClipPixel(Buf, X, Y, RGBToDWord(pData[I+2], pData[I+1], pData[I]));
        Inc(I, 3);
      end;
      for X:= 1 to (InfoHeader.biWidth mod 4) do
        Inc(I);
    end;
    SetLength(pData, 0);
    Close(F);
    {$IFDEF LOG}
    AddLog('(i)', Format(' >Texture loaded: "%s"', [Buf.Path]));
    {$ENDIF}
  end
  else
  begin
    {$IFDEF LOG}
    AddLog('(e)', Format(' >Cannot load Texture: "%s"', [AName]));
    {$ENDIF}
    if S2DInfo.Running then
      CloseWindow;
  end;
end;

procedure PutBuffer(var Dest, Source: TBuffer; X, Y: LongInt); overload; assembler;
{$IFNDEF OLDPROC}
var Area, vDX, vDY: Cardinal;
{$ENDIF}
asm
    mov edi,Dest
{$IFDEF OLDPROC}
    mov esi,Source
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov edx,[esi+4]
    add edx,X
    mov esi,[esi]
    mov eax,X
    mov ebx,Y
    xor ecx,ecx
@Lp:
    pusha
    push [esi]
    push ebx
    push eax
    push Dest
    call PutPixel
    popa
    inc ecx
    inc eax
    add esi,4
    cmp eax,edx
    jne @Lp
    mov eax,X
    inc ebx
    push esi
    mov esi,Source
    cmp ecx,[esi+16]
    jge @Ed
    pop esi
  //  mov esi,Source
    jmp @Lp
{$ELSE}
    xor ecx,ecx
    mov vDX,ecx
    mov vDY,ecx
    xor edx,edx
    mov esi,Source
    mov eax,Y
    cmp eax,[edi+32]
    jg  @Ed
    mov ebx,[esi+32]
    neg ebx
    cmp eax,ebx
    jle @Ed
    cmp eax,0
    jge @IgY
    neg eax
    mov vDY,eax
    mov Y,ecx
@IgY:
    mov eax,X
    cmp eax,[edi+28]
    jg  @Ed
    mov ebx,[esi+28]
    neg ebx
    cmp eax,ebx
    jle @Ed
    cmp eax,0
    jge @ESet0
    neg eax
    mov vDX,eax
    mov X,ecx

    cmp eax,0
    je  @ESet0
    mov ebx,[esi+4]
    sub ebx,eax
    jmp @ESet
@ESet0:
    mov ebx,[edi+4]
    sub ebx,X
    cmp ebx,[esi+4]
    jbe @ESet
    mov ebx,[esi+4]
    dec ebx
@ESet:
    mov eax,[edi+4]
    mul Y
    add eax,X
    mov Area,eax
    shl eax,2
    mov edi,[edi]
    add edi,eax
    mov edx,vDY
    mov eax,[esi+4]
    mul edx
    add eax,vDX
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx
//    xor edx,edx
    mov edx,vDY

@Lp:
    mov eax,[esi]
    mov [edi],eax
    add esi,4
    add edi,4
    inc ecx
    cmp ecx,ebx
    jne @Lp

    push edi
    mov edi,Dest
    mov eax,Area
    add eax,[edi+4]
    cmp eax,[edi+16]
    jae @Ed
    mov Area,eax
    pop edi
    mov eax,Source
    inc edx
    cmp edx,[eax+8]
    je  @Ed

    shl ecx,2
    sub esi,ecx
    add esi,[eax+36]
    sub edi,ecx
    mov eax,Dest
    add edi,[eax+36]

    xor ecx,ecx
    jmp @Lp
{$ENDIF}
@Ed:
end;

procedure PutBuffer(var Dest, Source: TBuffer; X, Y: LongInt; Mask: DWord); overload; assembler;
{$IFNDEF OLDPROC}
var Area, vDX, vDY: Cardinal;
{$ENDIF}
asm
    mov edi,Dest
{$IFDEF OLDPROC}
    mov esi,Source
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov edx,[esi+4]
    add edx,X
    mov esi,[esi]
    mov eax,X
    mov ebx,Y
    xor ecx,ecx
@Lp:
    pusha
    mov ecx,[esi]
    cmp ecx,Mask
    je @NoDraw
    push ecx
    push ebx
    push eax
    push Dest
    call PutPixel
@NoDraw:
    popa
    inc ecx
    inc eax
    add esi,4
    cmp eax,edx
    jne @Lp
    mov eax,X
    inc ebx
    push esi
    mov esi,Source
    cmp ecx,[esi+16]
    jge @Ed
    pop esi
  //  mov esi,Source
    jmp @Lp
{$ELSE}
    xor ecx,ecx
    mov vDX,ecx
    mov vDY,ecx
    xor edx,edx
    mov esi,Source
    mov eax,Y
    cmp eax,[edi+32]
    jg  @Ed
    mov ebx,[esi+32]
    neg ebx
    cmp eax,ebx
    jle @Ed
    cmp eax,0
    jge @IgY
    neg eax
    mov vDY,eax
    mov Y,ecx
@IgY:
    mov eax,X
    cmp eax,[edi+28]
    jg  @Ed
    mov ebx,[esi+28]
    neg ebx
    cmp eax,ebx
    jle @Ed
    cmp eax,0
    jge @ESet0
    neg eax
    mov vDX,eax
    mov X,ecx

    cmp eax,0
    je  @ESet0
    mov ebx,[esi+4]
    sub ebx,eax
    jmp @ESet
@ESet0:
    mov ebx,[edi+4]
    sub ebx,X
    cmp ebx,[esi+4]
    jbe @ESet
    mov ebx,[esi+4]
    dec ebx
@ESet:
    mov eax,[edi+4]
    mul Y
    add eax,X
    mov Area,eax
    shl eax,2
    mov edi,[edi]
    add edi,eax
    mov edx,vDY
    mov eax,[esi+4]
    mul edx
    add eax,vDX
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx
//    xor edx,edx
    mov edx,vDY

@Lp:
    mov eax,[esi]
    cmp eax,Mask
    je @NoDraw
    mov [edi],eax
@NoDraw:
    add esi,4
    add edi,4
    inc ecx
    cmp ecx,ebx
    jne @Lp

    push edi
    mov edi,Dest
    mov eax,Area
    add eax,[edi+4]
    cmp eax,[edi+16]
    jae @Ed
    mov Area,eax
    pop edi
    mov eax,Source
    inc edx
    cmp edx,[eax+8]
    je  @Ed

    shl ecx,2
    sub esi,ecx
    add esi,[eax+36]
    sub edi,ecx
    mov eax,Dest
    add edi,[eax+36]

    xor ecx,ecx
    jmp @Lp
{$ENDIF}
@Ed:
end;

procedure PutBuffer(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt); overload;
assembler;
var Size, SizeX2, SizeX1, I: DWord;
asm
    mov esi,Source
    mov edi,Dest
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov eax,[esi+4]
    shl eax,2
    mov SizeX2,eax

    mov eax,Width
    shl eax,2
    mov SizeX1,eax

    mov eax,Width
    mul Height
    mov Size,eax

    mov eax,[esi+4]
    mul YPos
    add eax,XPos
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx

    mov eax,Width
    mov I,eax

    mov eax,X
    mov ebx,Y

    mov edx,Width
    add edx,X

@Lp:
    pusha
    push [esi]
    push ebx
    push eax
    push Dest
    call PutPixel
    popa
    inc ecx
    inc eax
    add esi,4
 {   cmp ecx,Size
    jge @Ed }
    cmp eax,edx
    je @AddX
    jmp @Lp
@AddX:
    mov eax,I
    cmp eax,Size
    je @Ed
    add eax,Width
    mov I,eax
    add esi,SizeX2
    sub esi,SizeX1
    mov eax,X
    inc ebx
    jmp @Lp
@Ed:
end;

procedure PutBuffer(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt; Mask: DWord); overload;
assembler;
var Size, SizeX2, SizeX1, I: DWord;
asm
    mov esi,Source
    mov edi,Dest
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov eax,[esi+4]
    shl eax,2
    mov SizeX2,eax

    mov eax,Width
    shl eax,2
    mov SizeX1,eax

    mov eax,Width
    mul Height
    mov Size,eax

    mov eax,[esi+4]
    mul YPos
    add eax,XPos
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx

    mov eax,Width
    mov I,eax

    mov eax,X
    mov ebx,Y

    mov edx,Width
    add edx,X

@Lp:
    pusha
    mov ecx,[esi]
    cmp ecx,Mask
    je @NoDraw
    push ecx
    push ebx
    push eax
    push Dest
    call PutPixel
@NoDraw:
    popa
    inc ecx
    inc eax
    add esi,4
 {   cmp ecx,Size
    jge @Ed }
    cmp eax,edx
    je @AddX
    jmp @Lp
@AddX:
    mov eax,I
    cmp eax,Size
    je @Ed
    add eax,Width
    mov I,eax
    add esi,SizeX2
    sub esi,SizeX1
    mov eax,X
    inc ebx
    jmp @Lp
@Ed:
end;

procedure AddBuffer(var Dest, Source: TBuffer; X, Y: LongInt); overload; assembler;
{$IFNDEF OLDPROC}
var Area, vDX, vDY: Cardinal;
{$ENDIF}
asm
    mov edi,Dest
{$IFDEF OLDPROC}
    mov esi,Source
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov edx,[esi+4]
    add edx,X
    mov esi,[esi]
    mov eax,X
    mov ebx,Y
    xor ecx,ecx
@Lp:
    pusha
    push [esi]
    push ebx
    push eax
    push Dest
    call AddPixel
    popa
    inc ecx
    inc eax
    add esi,4
    cmp eax,edx
    jne @Lp
    mov eax,X
    inc ebx
    push esi
    mov esi,Source
    cmp ecx,[esi+16]
    jge @Ed
    pop esi
  //  mov esi,Source
    jmp @Lp
{$ELSE}
    xor ecx,ecx
    mov vDX,ecx
    mov vDY,ecx
    xor edx,edx
    mov esi,Source
    mov eax,Y
    cmp eax,[edi+32]
    jg  @Ed
    mov ebx,[esi+32]
    neg ebx
    cmp eax,ebx
    jle @Ed
    cmp eax,0
    jge @IgY
    neg eax
    mov vDY,eax
    mov Y,ecx
@IgY:
    mov eax,X
    cmp eax,[edi+28]
    jg  @Ed
    mov ebx,[esi+28]
    neg ebx
    cmp eax,ebx
    jle @Ed
    cmp eax,0
    jge @ESet0
    neg eax
    mov vDX,eax
    mov X,ecx

    cmp eax,0
    je  @ESet0
    mov ebx,[esi+4]
    sub ebx,eax
    jmp @ESet
@ESet0:
    mov ebx,[edi+4]
    sub ebx,X
    cmp ebx,[esi+4]
    jbe @ESet
    mov ebx,[esi+4]
    dec ebx
@ESet:
    mov eax,[edi+4]
    mul Y
    add eax,X
    mov Area,eax
    shl eax,2
    mov edi,[edi]
    add edi,eax
    mov edx,vDY
    mov eax,[esi+4]
    mul edx
    add eax,vDX
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx
//    xor edx,edx
    mov edx,vDY

@Lp:
    push ebx
    push ecx
    push edx
    mov eax,[edi]
    mov edx,eax
    xor ecx,ecx
    shr eax,16
    xor ah,ah
    mov ebx,[esi]
    shr ebx,16
    add ax,bx
    cmp ax,$FF
    jle @EdRed
    mov al,$FF
@EdRed:
    mov cl,al
    shl ecx,16
    mov al,dh
    xor ah,ah
    mov ebx,[esi]
    shr ebx,8
    xor bh,bh
    add ax,bx
    cmp ax,$FF
    jle @EdGreen
    mov al,$FF
@EdGreen:
    mov ch,al
    mov al,dl
    xor ah,ah
    mov ebx,[esi]
    xor bh,bh
    add ax,bx
    cmp ax,$FF
    jle @EdBlue
    mov al,$FF
@EdBlue:
    mov cl,al
    mov [edi],ecx
    pop edx
    pop ecx
    pop ebx
//    mov [edi],eax
    add esi,4
    add edi,4
    inc ecx
    cmp ecx,ebx
    jne @Lp

    push edi
    mov edi,Dest
    mov eax,Area
    add eax,[edi+4]
    cmp eax,[edi+16]
    jae @Ed
    mov Area,eax
    pop edi
    mov eax,Source
    inc edx
    cmp edx,[eax+8]
    je  @Ed

    shl ecx,2
    sub esi,ecx
    add esi,[eax+36]
    sub edi,ecx
    mov eax,Dest
    add edi,[eax+36]

    xor ecx,ecx
    jmp @Lp
{$ENDIF}
@Ed:
end;

procedure AddBuffer(var Dest, Source: TBuffer; X, Y: LongInt; Mask: DWord); overload; assembler;
{$IFNDEF OLDPROC}
var Area, vDX, vDY: Cardinal;
{$ENDIF}
asm
    mov edi,Dest
{$IFDEF OLDPROC}
    mov esi,Source
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov edx,[esi+4]
    add edx,X
    mov esi,[esi]
    mov eax,X
    mov ebx,Y
    xor ecx,ecx
@Lp:
    pusha
    mov ecx,[esi]
    cmp ecx,Mask
    je @NoDraw
    push ecx
    push ebx
    push eax
    push Dest
    call AddPixel
@NoDraw:
    popa
    inc ecx
    inc eax
    add esi,4
    cmp eax,edx
    jne @Lp
    mov eax,X
    inc ebx
    push esi
    mov esi,Source
    cmp ecx,[esi+16]
    jge @Ed
    pop esi
  //  mov esi,Source
    jmp @Lp
{$ELSE}
    xor ecx,ecx
    mov vDX,ecx
    mov vDY,ecx
    xor edx,edx
    mov esi,Source
    mov eax,Y
    cmp eax,[edi+32]
    jg  @Ed
    mov ebx,[esi+32]
    neg ebx
    cmp eax,ebx
    jle @Ed
    cmp eax,0
    jge @IgY
    neg eax
    mov vDY,eax
    mov Y,ecx
@IgY:
    mov eax,X
    cmp eax,[edi+28]
    jg  @Ed
    mov ebx,[esi+28]
    neg ebx
    cmp eax,ebx
    jle @Ed
    cmp eax,0
    jge @ESet0
    neg eax
    mov vDX,eax
    mov X,ecx

    cmp eax,0
    je  @ESet0
    mov ebx,[esi+4]
    sub ebx,eax
    jmp @ESet
@ESet0:
    mov ebx,[edi+4]
    sub ebx,X
    cmp ebx,[esi+4]
    jbe @ESet
    mov ebx,[esi+4]
    dec ebx
@ESet:
    mov eax,[edi+4]
    mul Y
    add eax,X
    mov Area,eax
    shl eax,2
    mov edi,[edi]
    add edi,eax
    mov edx,vDY
    mov eax,[esi+4]
    mul edx
    add eax,vDX
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx
//    xor edx,edx
    mov edx,vDY

@Lp:
    mov eax,[esi]
    cmp eax,Mask
    je  @NoDraw
    mov eax,[edi]
    push ebx
    push ecx
    push edx
    mov edx,eax
    xor ecx,ecx
    shr eax,16
    xor ah,ah
    mov ebx,[esi]
    shr ebx,16
    add ax,bx
    cmp ax,$FF
    jle @EdRed
    mov al,$FF
@EdRed:
    mov cl,al
    shl ecx,16
    mov al,dh
    xor ah,ah
    mov ebx,[esi]
    shr ebx,8
    xor bh,bh
    add ax,bx
    cmp ax,$FF
    jle @EdGreen
    mov al,$FF
@EdGreen:
    mov ch,al
    mov al,dl
    xor ah,ah
    mov ebx,[esi]
    xor bh,bh
    add ax,bx
    cmp ax,$FF
    jle @EdBlue
    mov al,$FF
@EdBlue:
    mov cl,al
    mov [edi],ecx
    pop edx
    pop ecx
    pop ebx
@NoDraw:
//    mov [edi],eax
    add esi,4
    add edi,4
    inc ecx
    cmp ecx,ebx
    jne @Lp

    push edi
    mov edi,Dest
    mov eax,Area
    add eax,[edi+4]
    cmp eax,[edi+16]
    jae @Ed
    mov Area,eax
    pop edi
    mov eax,Source
    inc edx
    cmp edx,[eax+8]
    je  @Ed

    shl ecx,2
    sub esi,ecx
    add esi,[eax+36]
    sub edi,ecx
    mov eax,Dest
    add edi,[eax+36]

    xor ecx,ecx
    jmp @Lp
{$ENDIF}
@Ed:
end;

procedure AddBuffer(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt); overload;
assembler;
var Size, SizeX2, SizeX1, I: DWord;
asm
    mov esi,Source
    mov edi,Dest
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov eax,[esi+4]
    shl eax,2
    mov SizeX2,eax

    mov eax,Width
    shl eax,2
    mov SizeX1,eax

    mov eax,Width
    mul Height
    mov Size,eax

    mov eax,[esi+4]
    mul YPos
    add eax,XPos
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx

    mov eax,Width
    mov I,eax

    mov eax,X
    mov ebx,Y

    mov edx,Width
    add edx,X

@Lp:
    pusha
    push [esi]
    push ebx
    push eax
    push Dest
    call AddPixel
    popa
    inc ecx
    inc eax
    add esi,4
 {   cmp ecx,Size
    jge @Ed }
    cmp eax,edx
    je @AddX
    jmp @Lp
@AddX:
    mov eax,I
    cmp eax,Size
    je @Ed
    add eax,Width
    mov I,eax
    add esi,SizeX2
    sub esi,SizeX1
    mov eax,X
    inc ebx
    jmp @Lp
@Ed:
end;

procedure AddBuffer(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt; Mask: DWord); overload;
assembler;
var Size, SizeX2, SizeX1, I: DWord;
asm
    mov esi,Source
    mov edi,Dest
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov eax,[esi+4]
    shl eax,2
    mov SizeX2,eax

    mov eax,Width
    shl eax,2
    mov SizeX1,eax

    mov eax,Width
    mul Height
    mov Size,eax

    mov eax,[esi+4]
    mul YPos
    add eax,XPos
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx

    mov eax,Width
    mov I,eax

    mov eax,X
    mov ebx,Y

    mov edx,Width
    add edx,X

@Lp:
    pusha
    mov ecx,[esi]
    cmp ecx,Mask
    je @NoDraw
    push ecx
    push ebx
    push eax
    push Dest
    call AddPixel
    popa
@NoDraw:
    inc ecx
    inc eax
    add esi,4
 {   cmp ecx,Size
    jge @Ed }
    cmp eax,edx
    je @AddX
    jmp @Lp
@AddX:
    mov eax,I
    cmp eax,Size
    je @Ed
    add eax,Width
    mov I,eax
    add esi,SizeX2
    sub esi,SizeX1
    mov eax,X
    inc ebx
    jmp @Lp
@Ed:
end;

procedure SubBuffer(var Dest, Source: TBuffer; X, Y: LongInt); overload; assembler;
{$IFNDEF OLDPROC}
var Area, vDX, vDY: Cardinal;
{$ENDIF}
asm
    mov edi,Dest
{$IFDEF OLDPROC}
    mov esi,Source
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov edx,[esi+4]
    add edx,X
    mov esi,[esi]
    mov eax,X
    mov ebx,Y
    xor ecx,ecx
@Lp:
    pusha
    push [esi]
    push ebx
    push eax
    push Dest
    call SubPixel
    popa
    inc ecx
    inc eax
    add esi,4
    cmp eax,edx
    jne @Lp
    mov eax,X
    inc ebx
    push esi
    mov esi,Source
    cmp ecx,[esi+16]
    jge @Ed
    pop esi
  //  mov esi,Source
    jmp @Lp
{$ELSE}
    xor ecx,ecx
    mov vDX,ecx
    mov vDY,ecx
    xor edx,edx
    mov esi,Source
    mov eax,Y
    cmp eax,[edi+32]
    jg  @Ed
    mov ebx,[esi+32]
    neg ebx
    cmp eax,ebx
    jle @Ed
    cmp eax,0
    jge @IgY
    neg eax
    mov vDY,eax
    mov Y,ecx
@IgY:
    mov eax,X
    cmp eax,[edi+28]
    jg  @Ed
    mov ebx,[esi+28]
    neg ebx
    cmp eax,ebx
    jle @Ed
    cmp eax,0
    jge @ESet0
    neg eax
    mov vDX,eax
    mov X,ecx

    cmp eax,0
    je  @ESet0
    mov ebx,[esi+4]
    sub ebx,eax
    jmp @ESet
@ESet0:
    mov ebx,[edi+4]
    sub ebx,X
    cmp ebx,[esi+4]
    jbe @ESet
    mov ebx,[esi+4]
    dec ebx
@ESet:
    mov eax,[edi+4]
    mul Y
    add eax,X
    mov Area,eax
    shl eax,2
    mov edi,[edi]
    add edi,eax
    mov edx,vDY
    mov eax,[esi+4]
    mul edx
    add eax,vDX
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx
//    xor edx,edx
    mov edx,vDY

@Lp:
    mov eax,[edi]
    push ebx
    push ecx
    push edx
    mov edx,eax
    xor ecx,ecx
    mov eax,[esi]
    mov ebx,edx
    shr eax,16
    shr ebx,16
    cmp al,bl
    ja @Zero1
    sub bl,al
    jmp @EdRed
@Zero1:
    xor bl,bl
@EdRed:
    mov cl,bl
    shl ecx,16
    mov eax,[esi]
    mov ebx,edx
    cmp ah,bh
    ja @Zero2
    sub bh,ah
    jmp @EdGreen
@Zero2:
    xor bh,bh
@EdGreen:
    mov ch,bh
    mov ebx,edx
    cmp al,bl
    ja @Zero3
    sub bl,al
    jmp @EdBlue
@Zero3:
    xor bl,bl
@EdBlue:
    mov cl,bl
    mov [edi],ecx
    pop edx
    pop ecx
    pop ebx

    add esi,4
    add edi,4
    inc ecx
    cmp ecx,ebx
    jne @Lp

    push edi
    mov edi,Dest
    mov eax,Area
    add eax,[edi+4]
    cmp eax,[edi+16]
    jae @Ed
    mov Area,eax
    pop edi
    mov eax,Source
    inc edx
    cmp edx,[eax+8]
    je  @Ed

    shl ecx,2
    sub esi,ecx
    add esi,[eax+36]
    sub edi,ecx
    mov eax,Dest
    add edi,[eax+36]

    xor ecx,ecx
    jmp @Lp
{$ENDIF}
@Ed:
end;

procedure SubBuffer(var Dest, Source: TBuffer; X, Y: LongInt; Mask: DWord); overload; assembler;
{$IFNDEF OLDPROC}
var Area, vDX, vDY: Cardinal;
{$ENDIF}
asm
    mov edi,Dest
{$IFDEF OLDPROC}
    mov esi,Source
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov edx,[esi+4]
    add edx,X
    mov esi,[esi]
    mov eax,X
    mov ebx,Y
    xor ecx,ecx
@Lp:
    pusha
    mov ecx,[esi]
    cmp ecx,Mask
    je @NoDraw
    push ecx
    push ebx
    push eax
    push Dest
    call SubPixel
@NoDraw:
    popa
    inc ecx
    inc eax
    add esi,4
    cmp eax,edx
    jne @Lp
    mov eax,X
    inc ebx
    push esi
    mov esi,Source
    cmp ecx,[esi+16]
    jge @Ed
    pop esi
  //  mov esi,Source
    jmp @Lp
{$ELSE}
    xor ecx,ecx
    mov vDX,ecx
    mov vDY,ecx
    xor edx,edx
    mov esi,Source
    mov eax,Y
    cmp eax,[edi+32]
    jg  @Ed
    mov ebx,[esi+32]
    neg ebx
    cmp eax,ebx
    jle @Ed
    cmp eax,0
    jge @IgY
    neg eax
    mov vDY,eax
    mov Y,ecx
@IgY:
    mov eax,X
    cmp eax,[edi+28]
    jg  @Ed
    mov ebx,[esi+28]
    neg ebx
    cmp eax,ebx
    jle @Ed
    cmp eax,0
    jge @ESet0
    neg eax
    mov vDX,eax
    mov X,ecx

    cmp eax,0
    je  @ESet0
    mov ebx,[esi+4]
    sub ebx,eax
    jmp @ESet
@ESet0:
    mov ebx,[edi+4]
    sub ebx,X
    cmp ebx,[esi+4]
    jbe @ESet
    mov ebx,[esi+4]
    dec ebx
@ESet:
    mov eax,[edi+4]
    mul Y
    add eax,X
    mov Area,eax
    shl eax,2
    mov edi,[edi]
    add edi,eax
    mov edx,vDY
    mov eax,[esi+4]
    mul edx
    add eax,vDX
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx
//    xor edx,edx
    mov edx,vDY

@Lp:
    mov eax,[esi]
    cmp eax,Mask
    je  @NoDraw
    mov eax,[edi]
    push ebx
    push ecx
    push edx
    mov edx,eax
    xor ecx,ecx
    mov eax,[esi]
    mov ebx,edx
    shr eax,16
    shr ebx,16
    cmp al,bl
    ja @Zero1
    sub bl,al
    jmp @EdRed
@Zero1:
    xor bl,bl
@EdRed:
    mov cl,bl
    shl ecx,16
    mov eax,[esi]
    mov ebx,edx
    cmp ah,bh
    ja @Zero2
    sub bh,ah
    jmp @EdGreen
@Zero2:
    xor bh,bh
@EdGreen:
    mov ch,bh
    mov ebx,edx
    cmp al,bl
    ja @Zero3
    sub bl,al
    jmp @EdBlue
@Zero3:
    xor bl,bl
@EdBlue:
    mov cl,bl
    mov [edi],ecx
    pop edx
    pop ecx
    pop ebx
@NoDraw:
    add esi,4
    add edi,4
    inc ecx
    cmp ecx,ebx
    jne @Lp

    push edi
    mov edi,Dest
    mov eax,Area
    add eax,[edi+4]
    cmp eax,[edi+16]
    jae @Ed
    mov Area,eax
    pop edi
    mov eax,Source
    inc edx
    cmp edx,[eax+8]
    je  @Ed

    shl ecx,2
    sub esi,ecx
    add esi,[eax+36]
    sub edi,ecx
    mov eax,Dest
    add edi,[eax+36]

    xor ecx,ecx
    jmp @Lp
{$ENDIF}
@Ed:
end;

procedure SubBuffer(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt); overload;
assembler;
var Size, SizeX2, SizeX1, I: DWord;
asm
    mov esi,Source
    mov edi,Dest
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov eax,[esi+4]
    shl eax,2
    mov SizeX2,eax

    mov eax,Width
    shl eax,2
    mov SizeX1,eax

    mov eax,Width
    mul Height
    mov Size,eax

    mov eax,[esi+4]
    mul YPos
    add eax,XPos
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx

    mov eax,Width
    mov I,eax

    mov eax,X
    mov ebx,Y

    mov edx,Width
    add edx,X

@Lp:
    pusha
    push [esi]
    push ebx
    push eax
    push Dest
    call SubPixel
    popa
    inc ecx
    inc eax
    add esi,4
 {   cmp ecx,Size
    jge @Ed }
    cmp eax,edx
    je @AddX
    jmp @Lp
@AddX:
    mov eax,I
    cmp eax,Size
    je @Ed
    add eax,Width
    mov I,eax
    add esi,SizeX2
    sub esi,SizeX1
    mov eax,X
    inc ebx
    jmp @Lp
@Ed:
end;

procedure SubBuffer(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt; Mask: DWord); overload;
assembler;
var Size, SizeX2, SizeX1, I: DWord;
asm
    mov esi,Source
    mov edi,Dest
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov eax,[esi+4]
    shl eax,2
    mov SizeX2,eax

    mov eax,Width
    shl eax,2
    mov SizeX1,eax

    mov eax,Width
    mul Height
    mov Size,eax

    mov eax,[esi+4]
    mul YPos
    add eax,XPos
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx

    mov eax,Width
    mov I,eax

    mov eax,X
    mov ebx,Y

    mov edx,Width
    add edx,X

@Lp:
    pusha
    mov ecx,[esi]
    cmp ecx,Mask
    je @NoDraw
    push ecx
    push ebx
    push eax
    push Dest
    call SubPixel
    popa
@NoDraw:
    inc ecx
    inc eax
    add esi,4
 {   cmp ecx,Size
    jge @Ed }
    cmp eax,edx
    je @AddX
    jmp @Lp
@AddX:
    mov eax,I
    cmp eax,Size
    je @Ed
    add eax,Width
    mov I,eax
    add esi,SizeX2
    sub esi,SizeX1
    mov eax,X
    inc ebx
    jmp @Lp
@Ed:
end;

procedure PutBufferMirrorX(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt); overload;
assembler;
var Size, SizeX2, SizeX1, I: DWord;
asm
    mov esi,Source
    mov edi,Dest
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov eax,[esi+4]
    shl eax,2
    mov SizeX2,eax

    mov eax,Width
    shl eax,2
    mov SizeX1,eax

    mov eax,Width
    mul Height
    mov Size,eax

    mov eax,[esi+4]
    mul YPos
    add eax,XPos
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx

    mov eax,Width
    mov I,eax

    add eax,X
    mov ebx,Y

    mov edx,Width
    add edx,X

@Lp:
    pusha
    push [esi]
    push ebx
    push eax
    push Dest
    call PutPixel
    popa
    inc ecx
    dec eax
    add esi,4
 {   cmp ecx,Size
    jge @Ed }
    cmp eax,edx
    je @AddX
    jmp @Lp
@AddX:
    mov eax,I
    cmp eax,Size
    je @Ed
    add eax,Width
    mov I,eax
    add esi,SizeX2
    sub esi,SizeX1
    mov eax,X
    add eax,Width
    inc ebx
    jmp @Lp
@Ed:
end;

procedure PutBufferMirrorX(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt; Mask: DWord); overload;
assembler;
var Size, SizeX2, SizeX1, I: DWord;
asm
    mov esi,Source
    mov edi,Dest
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov eax,[esi+4]
    shl eax,2
    mov SizeX2,eax

    mov eax,Width
    shl eax,2
    mov SizeX1,eax

    mov eax,Width
    mul Height
    mov Size,eax

    mov eax,[esi+4]
    mul YPos
    add eax,XPos
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx

    mov eax,Width
    mov I,eax

    mov eax,X
    add eax,Width
    mov ebx,Y

    mov edx,X

@Lp:
    pusha
    mov ecx,[esi]
    cmp ecx,Mask
    je @NoDraw
    push ecx
    push ebx
    push eax
    push Dest
    call PutPixel
@NoDraw:
    popa
    inc ecx
    dec eax
    add esi,4
 {   cmp ecx,Size
    jge @Ed }
    cmp eax,edx
    je @AddX
    jmp @Lp
@AddX:
    mov eax,I
    cmp eax,Size
    je @Ed
    add eax,Width
    mov I,eax
    add esi,SizeX2
    sub esi,SizeX1
    mov eax,X
    add eax,Width
    inc ebx
    jmp @Lp
@Ed:
end;

procedure AddBufferMirrorX(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt); overload;
assembler;
var Size, SizeX2, SizeX1, I: DWord;
asm
    mov esi,Source
    mov edi,Dest
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov eax,[esi+4]
    shl eax,2
    mov SizeX2,eax

    mov eax,Width
    shl eax,2
    mov SizeX1,eax

    mov eax,Width
    mul Height
    mov Size,eax

    mov eax,[esi+4]
    mul YPos
    add eax,XPos
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx

    mov eax,Width
    mov I,eax

    mov eax,X
    add eax,Width
    mov ebx,Y

    mov edx,X

@Lp:
    pusha
    push [esi]
    push ebx
    push eax
    push Dest
    call AddPixel
    popa
    inc ecx
    dec eax
    add esi,4
 {   cmp ecx,Size
    jge @Ed }
    cmp eax,edx
    je @AddX
    jmp @Lp
@AddX:
    mov eax,I
    cmp eax,Size
    je @Ed
    add eax,Width
    mov I,eax
    add esi,SizeX2
    sub esi,SizeX1
    mov eax,X
    add eax,Width
    inc ebx
    jmp @Lp
@Ed:
end;

procedure AddBufferMirrorX(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt; Mask: DWord); overload;
assembler;
var Size, SizeX2, SizeX1, I: DWord;
asm
    mov esi,Source
    mov edi,Dest
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov eax,[esi+4]
    shl eax,2
    mov SizeX2,eax

    mov eax,Width
    shl eax,2
    mov SizeX1,eax

    mov eax,Width
    mul Height
    mov Size,eax

    mov eax,[esi+4]
    mul YPos
    add eax,XPos
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx

    mov eax,Width
    mov I,eax

    add eax,X
    mov ebx,Y

    mov edx,X

@Lp:
    pusha
    mov ecx,[esi]
    cmp ecx,Mask
    je @NoDraw
    push ecx
    push ebx
    push eax
    push Dest
    call AddPixel
    popa
@NoDraw:
    inc ecx
    dec eax
    add esi,4
 {   cmp ecx,Size
    jge @Ed }
    cmp eax,edx
    je @AddX
    jmp @Lp
@AddX:
    mov eax,I
    cmp eax,Size
    je @Ed
    add eax,Width
    mov I,eax
    add esi,SizeX2
    sub esi,SizeX1
    mov eax,X
    add eax,Width
    inc ebx
    jmp @Lp
@Ed:
end;

procedure SubBufferMirrorX(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt); overload;
assembler;
var Size, SizeX2, SizeX1, I: DWord;
asm
    mov esi,Source
    mov edi,Dest
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov eax,[esi+4]
    shl eax,2
    mov SizeX2,eax

    mov eax,Width
    shl eax,2
    mov SizeX1,eax

    mov eax,Width
    mul Height
    mov Size,eax

    mov eax,[esi+4]
    mul YPos
    add eax,XPos
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx

    mov eax,Width
    mov I,eax

    add eax,X
    mov ebx,Y

    mov edx,X

@Lp:
    pusha
    push [esi]
    push ebx
    push eax
    push Dest
    call SubPixel
    popa
    inc ecx
    dec eax
    add esi,4
 {   cmp ecx,Size
    jge @Ed }
    cmp eax,edx
    je @AddX
    jmp @Lp
@AddX:
    mov eax,I
    cmp eax,Size
    je @Ed
    add eax,Width
    mov I,eax
    add esi,SizeX2
    sub esi,SizeX1
    mov eax,X
    add eax,Width
    inc ebx
    jmp @Lp
@Ed:
end;

procedure SubBufferMirrorX(var Dest, Source: TBuffer; X, Y, XPos, YPos, Width, Height: LongInt; Mask: DWord); overload;
assembler;
var Size, SizeX2, SizeX1, I: DWord;
asm
    mov esi,Source
    mov edi,Dest
    mov eax,X
    mov ebx,Y

    shr eax,31
    cmp eax,0
    je @CheckX
    jmp @CheckM1
@ContinueCheck:
    shr ebx,31
    cmp ebx,0
    je @CheckY
    jmp @CheckM2

@CheckX:
    mov eax,X
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckY:
    mov ebx,Y
    cmp ebx,[edi+8]
    jge @Ed
    jmp @EndCheck

@CheckM1:
    mov eax,X
    sub eax,$FFFFFFFF
    cmp eax,[edi+4]
    jge @Ed
    jmp @ContinueCheck

@CheckM2:
    mov eax,Y
    sub eax,$FFFFFFFF
    cmp eax,[edi+8]
    jge @Ed

@EndCheck:
    mov eax,[esi+4]
    shl eax,2
    mov SizeX2,eax

    mov eax,Width
    shl eax,2
    mov SizeX1,eax

    mov eax,Width
    mul Height
    mov Size,eax

    mov eax,[esi+4]
    mul YPos
    add eax,XPos
    shl eax,2
    mov esi,[esi]
    add esi,eax
    xor ecx,ecx

    mov eax,Width
    mov I,eax

    add eax,X
    mov ebx,Y

    mov edx,X

@Lp:
    pusha
    mov ecx,[esi]
    cmp ecx,Mask
    je @NoDraw
    push ecx
    push ebx
    push eax
    push Dest
    call SubPixel
    popa
@NoDraw:
    inc ecx
    dec eax
    add esi,4
 {   cmp ecx,Size
    jge @Ed }
    cmp eax,edx
    je @AddX
    jmp @Lp
@AddX:
    mov eax,I
    cmp eax,Size
    je @Ed
    add eax,Width
    mov I,eax
    add esi,SizeX2
    sub esi,SizeX1
    mov eax,X
    add eax,Width
    inc ebx
    jmp @Lp
@Ed:
end;

procedure SysText(Dest: TBuffer; X, Y: LongInt; Tex: String; Color: LongInt);
var I, J, K: Byte;
begin
  for I:= 0 to Length(Tex)-1 do
    for J:= 0 to 7 do
      for K:= 0 to 7 do
        if ((SysFont[Byte(Tex[I+1])*8+J] shl K) AND 128) <> 0 then
          PutPixel(Dest, X+K+I*8, Y+J, Color);
end;

procedure StretchBuffer(var Dest, Source: TBuffer; X, Y, ResizeX, ResizeY: LongInt); assembler;
// resize buffer
var
  FX, FY  : Single;
asm
    mov   esi,Source
    mov   edi,Dest
    fild  dword ptr [esi+4]
    fidiv dword ptr ResizeX
    fstp  FX
    fild  dword ptr [esi+8]
    fidiv dword ptr ResizeY
    fstp  FY
    fld   FX     // st(2)
    fld   FY     // st(1)

    mov   eax,X
    add   eax,ResizeX
    sub   eax,2

    mov   ebx,Y
    add   ebx,ResizeY
    sub   ebx,2
    push  ebx
    mov   ebx,Y
@Lp1:
    xor   ecx,ecx
    mov   FX,ecx
    mov   ecx,X
@Lp2:
    push  eax
    sub   esp,4
    fld   FY
    fistp dword ptr [esp]

    sub   esp,4
    fld   FX
    fadd  st(2)
    fst   FX
    fistp dword ptr [esp]

    push  Source
    call  GetUnClipPixel

    push  eax
    push  ebx
    push  ecx
    push  edi
    call  PutPixel
    pop   eax
    inc   ecx
    cmp   ecx,eax
    jne   @Lp2
    inc   ebx
    cmp   ebx,[esp]
    je    @EndP
    fld   FY
    fadd  st(1)
    fstp  FY
    jmp    @Lp1
@EndP:
    fistp FY
    fistp FY    // pop st
    pop   ebx
end;

procedure RotateBuffer(var Dest, Source: TBuffer; X, Y, Angle: LongInt); //assembler;
// Rotate buffer - toc do nhanh hon pure pascal 70%
var
  Rad               : Single = DEG2RAD;
  sinTheta, cosTheta: Single;
  CenterX, CenterY  : Cardinal;
  Limit, StartX,
  iPrime, jPrime    : LongInt;
begin
  asm
    mov   edi,Dest
    neg   Angle
    fild  Angle
    fmul  Rad
    fst   Rad
    fsin
    fstp  sinTheta
    fld   Rad
    fcos
    fstp  cosTheta
    mov   esi,Source
    mov   eax,[esi+24]
    mov   CenterY,eax
    mov   eax,[esi+20]
    mov   CenterX,eax
    cmp   eax,CenterY
    jle   @CenterAsY
    jmp   @PrepLp
@CenterAsY:
    mov   eax,CenterY
@PrepLp:
    shr   eax,1
    mov   ebx,eax
    neg   eax
    mov   Limit,eax
    neg   eax
    add   ebx,[esi+8]
    add   eax,[esi+4]
    mov   StartX,eax
@Lp1:
    mov   eax,ebx
    sub   eax,CenterY
    mov   jPrime,eax
    mov   ecx,StartX
@Lp2:
    sub   esp,4
    mov   eax,ecx
    sub   eax,CenterX
    mov   iPrime,eax

    fild  iPrime
    fmul  cosTheta
    fild  jPrime
    fmul  sinTheta
    fsubp st(1),st
    fistp dword ptr [esp]
    mov   edx,[esp]
    add   edx,CenterX  // -

    fild  jPrime
    fmul  cosTheta
    fild  iPrime
    fmul  sinTheta
    faddp st(1),st(0)
    fistp dword ptr [esp]
    mov   eax,[esp]
    add   eax,CenterY  // -
    add   esp,4

    mov   esi,Source
    cmp   eax,[esi+32]
    ja    @NoDraw
    cmp   edx,[esi+28]
    ja    @NoDraw
    push  eax
    push  edx
    push  Source
    call  GetPixel
    push  eax
    mov   eax,ebx
    add   eax,Y     // -
    push  eax
    mov   eax,ecx
    add   eax,X     // -
    push  eax
    push  edi
    call  PutPixel
@NoDraw:
    dec   ecx       //,-1
    cmp   ecx,Limit
    jne   @Lp2
    dec   ebx       //,-1
    cmp   ebx,Limit
    jne   @Lp1
  end;
end;

end.

